package com.ruoyi.framework.security;

import com.ruoyi.common.utils.JwtTokenUtil;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.system.service.aggregation.IAggUserService;
import com.ruoyi.system.domain.aggregation.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import java.util.HashSet;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 统一Token认证过滤器
 * 所有接口统一使用JWT Token认证
 * - 系统管理用户：username = admin
 * - 聚合码用户：username = agg_{userId}
 * 
 * @author ruoyi
 */
@Component
public class UnifiedTokenFilter extends OncePerRequestFilter
{
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private IAggUserService aggUserService;

    private static final String TOKEN_HEADER = "Authorization";
    private static final String BEARER_PREFIX = "Bearer ";
    private static final String REDIS_TOKEN_PREFIX = "agg:token:";
    
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    // 白名单路径（不需要token验证）
    private static final String[] WHITELIST = {
        "/login", "/register", "/captchaImage",
        "/agg/user/login", "/agg/user/appLogin", "/agg/user/forget",
        "/agg/sms/sendCode", "/agg/sms/send", "/agg/callback/**", "/agg/qrcode/scan",
        "/agg/test/**"
    };

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException
    {
        String requestUri = request.getRequestURI();
        System.out.println("===== UnifiedTokenFilter Debug =====");
        System.out.println("Request URI: " + requestUri);
        
        // 检查白名单
        for (String pattern : WHITELIST)
        {
            System.out.println("Checking pattern: " + pattern + " against " + requestUri);
            if (pathMatcher.match(pattern, requestUri))
            {
                System.out.println("✅ MATCHED! Allowing request without token");
                chain.doFilter(request, response);
                return;
            }
        }
        System.out.println("❌ No whitelist match, checking token...");
        
        // 尝试从多个位置获取token
        String token = getTokenFromRequest(request);
        
        if (token != null && !token.isEmpty())
        {
            // 统一使用JWT Token
            handleJwtToken(token, request);
        }
        else if (!isWhitelisted(requestUri))
        {
            // 不在白名单且没有token，返回401
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"msg\":\"未登录或token已过期\"}");
            return;
        }

        chain.doFilter(request, response);
    }
    
    /**
     * 从请求中获取token（支持多种方式）
     */
    private String getTokenFromRequest(HttpServletRequest request)
    {
        // 方式1：从 Authorization Header 获取（标准方式）
        String authHeader = request.getHeader(TOKEN_HEADER);
        if (authHeader != null && !authHeader.isEmpty())
        {
            // 去除 Bearer 前缀（如果有）
            if (authHeader.startsWith(BEARER_PREFIX))
            {
                return authHeader.substring(BEARER_PREFIX.length());
            }
            return authHeader;
        }
        
        // 方式2：从 token Header 获取（兼容小写）
        String tokenHeader = request.getHeader("token");
        if (tokenHeader != null && !tokenHeader.isEmpty())
        {
            return tokenHeader;
        }
        
        // 方式3：从 URL 参数 token 获取
        String tokenParam = request.getParameter("token");
        if (tokenParam != null && !tokenParam.isEmpty())
        {
            return tokenParam;
        }
        
        return null;
    }
    
    /**
     * 检查路径是否在白名单
     */
    private boolean isWhitelisted(String requestUri)
    {
        for (String pattern : WHITELIST)
        {
            if (pathMatcher.match(pattern, requestUri))
            {
                return true;
            }
        }
        return false;
    }

    /**
     * 处理JWT Token（混合验证：JWT签名 + Redis存储）
     */
    private void handleJwtToken(String token, HttpServletRequest request)
    {
        try
        {
            // 第1步：验证JWT签名和过期时间
            String username = jwtTokenUtil.getUsernameFromToken(token);
            
            if (username != null && SecurityContextHolder.getContext().getAuthentication() == null)
            {
                if (jwtTokenUtil.validateToken(token, username))
                {
                    Long userId = jwtTokenUtil.getUserIdFromToken(token);
                    
                    // 第2步：如果是聚合码用户，检查Redis（实现单点登录、踢人功能）
                    if (username.startsWith("agg_"))
                    {
                        String redisKey = REDIS_TOKEN_PREFIX + userId;
                        Object redisToken = redisTemplate.opsForValue().get(redisKey);
                        
                        // Redis验证：确保是最新token（单点登录）
                        if (redisToken != null && token.equals(redisToken))
                        {
                            // ✅ JWT有效 + Redis中存在 → 通过验证
                            request.setAttribute("userId", userId);
                            setAuthenticationForAggregationUser(userId, username, request);
                            
                            System.out.println("✅ JWT+Redis混合验证通过，userId: " + userId);
                        }
                        else if (redisToken == null)
                        {
                            // Redis中没有token（被主动踢下线或Redis故障）
                            // 降级：如果JWT本身有效，仍然允许访问（可选）
                            System.out.println("⚠️ Redis中无token，但JWT有效，降级通过");
                            request.setAttribute("userId", userId);
                            setAuthenticationForAggregationUser(userId, username, request);
                        }
                        else
                        {
                            // Redis中的token和当前token不一致（被其他设备登录踢下线）
                            System.out.println("❌ 单点登录检测：token已被新登录覆盖");
                        }
                    }
                    // 系统管理用户，只验证JWT
                    else
                    {
                        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                                userDetails, null, userDetails.getAuthorities());
                        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                        
                        System.out.println("✅ 系统管理用户JWT验证通过: " + username);
                    }
                }
            }
        }
        catch (Exception e)
        {
            System.out.println("❌ Token验证异常: " + e.getMessage());
        }
    }
    
    /**
     * 为聚合码用户设置Authentication
     */
    private void setAuthenticationForAggregationUser(Long userId, String username, HttpServletRequest request)
    {
        try
        {
            // 从数据库获取用户信息
            User aggUser = aggUserService.selectUserById(userId);
            if (aggUser != null)
            {
                // 将聚合码用户转换为SysUser
                SysUser sysUser = convertAggUserToSysUser(aggUser);
                
                // 创建LoginUser对象
                LoginUser loginUser = new LoginUser();
                loginUser.setUserId(userId);
                loginUser.setUser(sysUser);
                loginUser.setPermissions(new HashSet<>()); // 聚合码用户暂时不设置权限
                
                // 设置到SecurityContext
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        loginUser, null, loginUser.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                SecurityContextHolder.getContext().setAuthentication(authentication);
                
                System.out.println("✅ 聚合码用户Authentication设置成功，userId: " + userId);
            }
            else
            {
                System.out.println("❌ 聚合码用户不存在，userId: " + userId);
            }
        }
        catch (Exception e)
        {
            System.out.println("❌ 设置聚合码用户Authentication失败: " + e.getMessage());
        }
    }
    
    /**
     * 将聚合码用户转换为SysUser
     */
    private SysUser convertAggUserToSysUser(User aggUser)
    {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(aggUser.getId());
        sysUser.setUserName(aggUser.getName());
        sysUser.setPhonenumber(aggUser.getPhone());
        sysUser.setEmail(aggUser.getEmail());
        sysUser.setAvatar(aggUser.getAvatar());
        sysUser.setStatus("0"); // 正常状态
        sysUser.setDelFlag("0"); // 未删除
        return sysUser;
    }
}

